/*
 *  FILE: 
 *  	xdirent.c
 *
 *  DESCRIPTION:
 *  	A set of functions used for loading a directory structure into
 *      a "struct xdirent *" array.   EVERY call of xdirent_list MUST
 *      be followed by a xdirent_list_free, the number of members is required!
 *
 *  FUNCTIONS:
 *      xdirent_alphasort()   - Portable alphasort rewrite. uses string_cmp from local string.h
 *      xdirent_r_alphasort() - "Reversed" xdirent_alphasort(). 
 *  	xdirent_list()        - Fill array of dirents using directory fd.
 *  	xdirent_list_free()   - Free any data allocated by dirent_list().
 *
 *
 *
 * Copyright (c) 2004-2006 Karlan Thomas Mitchell<karlanmitchell@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *         This product includes software developed by
           Karlan Thomas Mitchell<karlanmitchell@gmail.com>
 * 4. Neither Karlan Thomas Mitchell nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY KARLAN THOMAS MITCHELL AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


#include "xdirent.h"




int signed xdirent_alphasort(const void *a, const void *b){
	return string_cmp( ((struct xdirent *)a)->d_name, ((struct xdirent *)b)->d_name);
	}

int signed xdirent_r_alphasort(const void *a, const void *b){
	return (string_cmp( ((struct xdirent *)b)->d_name, ((struct xdirent *)a)->d_name ) * -1);
	}


/* NOTE: directory must be OPENED AND READ FOR READING! */
size_t xdirent_list(DIR * dirfd, struct xdirent ** dirent_struct){
		
		
		
	struct dirent *  cur_entry;
	size_t           dname_len;
	size_t           listing_items  =  0;
	size_t           items_used     =  0;
	size_t           malloc_advance =  10; /*The number of items to malloc in advance when everything is full*/
	
	
	/*create (var)malloc_advance items at first*/
	*dirent_struct  = (struct xdirent *)malloc( malloc_advance * sizeof(struct xdirent) );
	if(*dirent_struct == NULL)
		return 0;
		
		
	listing_items = malloc_advance;
		
				
	while(1){
		cur_entry = readdir(dirfd);
		
		if(cur_entry == NULL)
			break;
		
		/*Remove this if you want to show files/directories which begin with '.'*/
		if(cur_entry->d_name[0] == '.')
			continue;	

		dname_len = strlen(cur_entry->d_name) + 1;

		(*dirent_struct)[items_used].d_name = malloc( dname_len * sizeof(char)) ;
		if((*dirent_struct)[items_used].d_name == NULL){
              		fprintf(stderr, "MALLOC ERROR\n");
              		exit(-552203);
        		}
		
		strlcpy((*dirent_struct)[items_used].d_name, cur_entry->d_name, dname_len);
		
		/*Kinda a long shot, but I guess it works*/
		#ifndef __BSDSYSTEM__
		(*dirent_struct)[items_used].d_ino = cur_entry->d_ino;
		#endif
		
		
		items_used++;
		
		
		/*We used the last space allocate more space*/
		if(items_used % malloc_advance == 0){
			listing_items += malloc_advance;
			*dirent_struct = (struct xdirent *)realloc( *dirent_struct, listing_items * sizeof(struct xdirent) );
		}
	}
    if(items_used == 0)
            free(*dirent_struct);
            
            
	return items_used;
}

/*cleans up dirent_list parallel dirent data(ie frees alloced data)*/
size_t xdirent_list_free(struct xdirent ** dirent_struct, size_t nmebs){
    if(nmebs == 0)/*list frees everything is nmebs is zero :-D*/
             return 0;
    
	size_t cur_nmebs = nmebs - 1;
	while (1){ /*Don't check cur_nmebs here, because of unsigned issues.*/
		free((*dirent_struct)[cur_nmebs].d_name);
		if(cur_nmebs == 0)
			break;
		cur_nmebs--;
	}

	free((*dirent_struct));
	return 0;
}
